package com.wu.http.server;


import com.wu.javax.servlet.ServletContext;
import com.wu.javax.servlet.http.HttpServletRequest;
import com.wu.javax.servlet.http.HttpSession;
import com.wu.util.TomcatUtil;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import static com.wu.constant.Constant.*;

/**
 * 由服务器实现的Http请求的类，主要是解析 http请求头，取出参数存到 Map 中
 */
public class MyHttpServletRequest implements HttpServletRequest {
    /**
     * 请求方法
     */
    private String method;
    /**
     * 协议版本
     */
    private String protocol;
    /**
     * 服务器名
     */
    private String serverName;
    /**
     * 端口
     */
    private int serverPort;
    /**
     * 资源的地址
     */
    private String requestURI;
    /**
     * 资源全路径
     */
    private String requestURL;
    /**
     * 上下文路径 : 项目路径
     */
    private String contextPath;
    /**
     * 项目在服务器的真实路径
     */
    private final String realPath = System.getProperty("user.dir") + "/webapps";

    /**
     * 输入流
     */
    private final InputStream iis;
    /**
     * 请求字符串  地址栏中  地址的后面的一部分
     */
    private String queryString;

    private String jsonParams;

    private String sessionId;

    /**
     * 所有的头信息
     */
    private final Map<String, String> headers = new HashMap<>();

    public MyHttpServletRequest(InputStream iis) {
        this.iis = iis;
        parseRequest();
    }

    @Override
    public String getRealPath() {
        return realPath;
    }

    public String getSessionId() {
        return this.sessionId;
    }

    /**
     * 解析请求
     */
    @Override
    public void parseRequest() {
        // 从输入流中读取信息
        String requestInfoString = readFromInputStream();
        if ("".equals(requestInfoString)) {
            return;
        }
        // 解析requestInfo字符串
        parseRequestInfoString(requestInfoString);
    }

    /**
     * 解析从请求中获取的信息
     */
    private void parseRequestInfoString(String requestInfoString) {
        StringTokenizer st = new StringTokenizer(requestInfoString);
        if (st.hasMoreTokens()) {
            //获取请求的方法  post 还是  get
            this.method = st.nextToken();
            //请求的URI :  /ROOT/index.html
            this.requestURI = st.nextToken();
            //协议 ： HTTP/1.1
            this.protocol = st.nextToken();
            //应用上下文路径 ： /ROOT
            this.contextPath = "/" + this.requestURI.split("/")[1];
            //请求全路径
            this.requestURL = this.realPath + requestURI;
            //端口
            try {
                this.serverPort = TomcatUtil.parseServerXml();
            } catch (Exception e) {
                e.printStackTrace();
            }
            parseRequestParameter(requestInfoString);
            parseHeader(requestInfoString);
        }
    }

    /**
     * 解析请求头
     */
    private void parseHeader(String requestInfoString) {
        //取出\r\n\r\n前面的
        String header = requestInfoString.substring(0, requestInfoString.indexOf("\r\n\r\n"));
        String[] heads = header.split("\r\n");
        if (heads.length > 0) {
            for (int i = 1; i < heads.length; i++) {
                //取出一行
                String[] head = heads[i].split(": ");
                headers.put(head[0], head[1]);
            }
        }
        getSession();
    }

    /**
     * 解析请求的参数
     * 暂时只支持表单形式接收
     * json待写
     */
    private void parseRequestParameter(String protocol) {
        if (REQUEST_METHOD_GET.equalsIgnoreCase(this.method)) {
            /**
             * 请求URI：/ROOT/login?name=admin&password=123456
             * queryString = name=admin&password=123456
             */
            int index = requestURI.indexOf(SPLIT_HOW);
            if (index < 0) {
                //说明是Get请求，但是没有参数
                return;
            }
            this.queryString = requestURI.substring(requestURI.indexOf(SPLIT_HOW) + 1);
            /**
             * 请求URI：/ROOT/app.HelloServlet.do?name=admin&password=123456
             * requestURI = /ROOT/app.HelloServlet.do
             */
            //进一步处理 请求路径
            this.requestURI = requestURI.substring(0, requestURI.indexOf(SPLIT_HOW));
            //从queryString中解析出参数   name=admin     password=123456
            String[] queryStringSplit = this.queryString.split(SPLIT_AND);
            putParams(queryStringSplit);
        }
        if (REQUEST_METHOD_POST.equalsIgnoreCase(this.method)) {
            //post实体中的参数
            String protocolSub = protocol.substring(protocol.indexOf("\r\n\r\n") + 4);
            if (protocolSub.length() > 0) {
                if (protocolSub.startsWith("{") && protocolSub.endsWith("}")) {
                    //说明是json传参
                    setJsonParams(protocolSub);
                } else {
                    String[] protocolSubSplit = protocolSub.split(SPLIT_AND);
                    putParams(protocolSubSplit);
                }
            }
        }
    }

    private void putParams(String[] protocolSubSplit) {
        if (protocolSubSplit.length > 0) {
            for (String params : protocolSubSplit) {
                String[] param = params.split(SPLIT_EQUALS);
                if (param.length > 1) {
                    //  参数名 : 值
                    this.parameters.put(param[0], param[1]);
                } else {
                    //  参数名 : 值
                    this.parameters.put(param[0], null);
                }
            }
        }
    }

    public String getQueryString() {
        return this.queryString;
    }

    /**
     * 从输入流中读取信息
     *
     * @return
     */
    private String readFromInputStream() {
        // 1. 从input中读出所有的内容( http请求协议 =》 protocol)
        String protocol;
        // 从流中取  protocol
        StringBuffer stringBuffer = new StringBuffer(1024 * 10);
        int length;
        byte[] bs = new byte[1024 * 10];
        try {
            length = this.iis.read(bs);
        } catch (IOException e) {
            e.printStackTrace();
            length = -1;
        }
        for (int j = 0; j < length; j++) {
            stringBuffer.append((char) bs[j]);
        }
        protocol = stringBuffer.toString();
        return protocol;
    }

    @Override
    public String getMethod() {
        return method;
    }

    public String getProtocol() {
        return protocol;
    }

    @Override
    public String getServerName() {
        return serverName;
    }

    @Override
    public int getServerPort() {
        return serverPort;
    }

    @Override
    public String getRequestURI() {
        return requestURI;
    }

    @Override
    public String getHeader(String name) {
        return headers.getOrDefault(name, null);
    }

    @Override
    public ServletContext getServletContext() {
        return MyServletContext.getInstance();
    }

    @Override
    public HttpSession getSession() {
        HttpSession session = null;
        String cookieValue = headers.get("Cookie");
        if (cookieValue != null && cookieValue.trim().length() > 0) {
            String[] cookies = cookieValue.split(";");
            for (String cookie : cookies) {
                String[] ck = cookie.split("=");
                if (SESSION_ID.equals(ck[0])) {
                    this.sessionId = ck[1];
                    break;
                }
            }
        }
        if (sessionId != null && !"".equals(sessionId)) {
            session = MyHttpSessionContext.getInstance().getSession(sessionId);
        }
        if (session == null) {
            session = new MyHttpSession();
            this.sessionId = session.getId();
        }
        return session;
    }

    public String getRequestURL() {
        return requestURL;
    }

    public String getContextPath() {
        return contextPath;
    }

    private final Map<String, Object> attributes = new HashMap<>();

    @Override
    public Object getAttribute(String key) {
        return attributes.get(key);
    }

    @Override
    public void setAttribute(String key, Object value) {
        attributes.put(key, value);
    }

    private final Map<String, String> parameters = new HashMap<>();

    @Override
    public String getParameter(String key) {
        return parameters.get(key);
    }

    @Override
    public Map<String, String> getParameterMap() {
        return this.parameters;
    }

    public void setJsonParams(String jsonParams) {
        this.jsonParams = jsonParams;
    }

    @Override
    public String getJsonParams() {
        return this.jsonParams;
    }
}
